package com.ml.loan.common.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;

/**
 * 异步线程池配置
 *
 * @author Mickey
 * @date 2022/2/15 17:44
 */
@Slf4j
@Configuration
public class AsycTaskConfig {

    @Bean
    public TaskExecutor taskExcutor() {
        //@Async使用自定义的CustomThreadPoolTaskExecutor搭配TransmittableThreadLocal实现父子线程数据传递
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数
        executor.setCorePoolSize(10);
        //最大线程数
        executor.setMaxPoolSize(50);
        //队列
        executor.setQueueCapacity(1000);
        //线程池名称
        executor.setThreadNamePrefix("Async-Executor-");
        /*
           rejection-policy：当pool已经达到max size的时候，如何处理新任务
           CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待30秒后强制停止
        executor.setAwaitTerminationSeconds(30);
        //异步线程获取日志上下文
        executor.setTaskDecorator(new MdcTaskDecorator());
        executor.initialize();
        return executor;
    }


    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(20,
                new BasicThreadFactory.Builder().namingPattern("Async-Manager-Executor-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                printScheduledExecutorException(r, t);
            }
        };
    }


    /**
     * 打印线程异常信息
     */
    public static void printScheduledExecutorException(Runnable r, Throwable t) {
        if (t == null && r instanceof Future<?>) {
            try {
                Future<?> future = (Future<?>) r;
                if (future.isDone()) {
                    future.get();
                }
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null) {
            log.error("异步任务执行异常：{}", t.getMessage(), t);
        }
    }
}
